/**
 * 文件名：****.java
 * 版权：Copyright Lightkit All Rights Reserved.
 * 描述：*****
 */
package com.lightkits.wms.domain.saleticket.impl;


import com.lightkits.common.TransactionValidate;
import com.lightkits.common.db.entity.BdTag;
import com.lightkits.common.db.entity.FndItemBase;
import com.lightkits.common.db.entity.FndOrganizationBase;
import com.lightkits.common.db.entity.FndWorker;
import com.lightkits.common.db.entity.WmSaleTicketLine;
import com.lightkits.common.db.entity.WmSalesTicket;
import com.lightkits.common.db.entity.event.BdEvent;
import com.lightkits.common.db.entity.event.BdEventRecord;
import com.lightkits.framework.common.exception.LightKitsBizException;
import com.lightkits.framework.common.logging.Logger;
import com.lightkits.framework.common.logging.LoggerFactory;
import com.lightkits.framework.common.model.CheckResult;
import com.lightkits.framework.common.model.IResult;
import com.lightkits.framework.common.utility.json.JsonUtil;
import com.lightkits.framework.common.utility.object.ObjectUtil;
import com.lightkits.framework.common.utility.validate.IntegrityValidator;
import com.lightkits.wms.domain.saleticket.CreateChangeParams;
import com.lightkits.wms.domain.saleticket.CreateSaleEventService;
import com.lightkits.wms.domain.saleticket.CreateSaleParamsService;
import com.lightkits.wms.domain.saleticket.CreateUpSaleTicketService;
import com.lightkits.wms.domain.saleticket.model.SaleConstrant;
import com.lightkits.wms.domain.saleticket.repo.WmSaleTicketLineService;
import com.lightkits.wms.domain.saleticket.repo.WmSaleTicketService;
import com.lightkits.wms.domain.saveonhand.models.OnhandParams;
import com.lightkits.wms.domain.saveonhand.repo.BdEventRecordService;
import com.lightkits.wms.domain.saveonhand.repo.BdEventService;
import com.lightkits.wms.domain.saveonhand.service.UseParamsDomain;
import com.lightkits.wms.domain.stocktransfer.service.SubStockTransferDomain;
import com.lightkits.wms.domain.tagservice.UseTagParamsService;
import com.lightkits.wms.dto.onhand.model.OnhandDTO;
import com.lightkits.wms.dto.saleticket.model.UpSaleTicketHeadDto;
import com.lightkits.wms.dto.saleticket.model.UpSaleTicketLineDto;
import com.lightkits.wms.dto.stocktransfer.model.SubStockViewDTO;
import com.lightkits.wms.dto.tagservice.model.CancelTagDto;
import com.lightkits.wms.dto.tagservice.model.TagViewDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author jing.wei@hand-china.com
 * @date 2019/7/1 11:09
 **/
@Service
public class CreateUpSaleTicketServiceImpl implements CreateUpSaleTicketService {
    private static final Logger LOGGER = LoggerFactory.getLogger(CreateUpSaleTicketServiceImpl.class);

    private final WmSaleTicketLineService saleTicketLineService;
    private final WmSaleTicketService saleTicketService;
    private final BdEventRecordService bdEventRecordService;
    private final BdEventService bdEventService;
    private final CreateSaleParamsService createSaleParamsService;
    private final CreateSaleEventService createSaleEventService;
    private final UseTagParamsService useTagParamsService;
    private final CreateChangeParams createChangeParams;
    private final UseParamsDomain useParamsDomain;
    private final SubStockTransferDomain subStockTransferDomain;

    @Autowired
    public CreateUpSaleTicketServiceImpl(WmSaleTicketLineService saleTicketLineService,
                                         WmSaleTicketService saleTicketService,
                                         BdEventRecordService bdEventRecordService,
                                         BdEventService bdEventService,
                                         CreateSaleParamsService createSaleParamsService,
                                         CreateSaleEventService createSaleEventService,
                                         UseTagParamsService useTagParamsService,
                                         CreateChangeParams createChangeParams,
                                         UseParamsDomain useParamsDomain,
                                         SubStockTransferDomain subStockTransferDomain) {
        this.saleTicketLineService = saleTicketLineService;
        this.saleTicketService = saleTicketService;
        this.bdEventRecordService = bdEventRecordService;
        this.bdEventService = bdEventService;
        this.createSaleParamsService = createSaleParamsService;
        this.createSaleEventService = createSaleEventService;
        this.useTagParamsService = useTagParamsService;
        this.createChangeParams = createChangeParams;
        this.useParamsDomain = useParamsDomain;
        this.subStockTransferDomain = subStockTransferDomain;
    }

    /**
     * 售货单参数校验
     *
     * @param headDto  售货单头信息
     * @param lineDtos 售货单行信息
     * @return IResult
     **/
    private IResult checkParams(UpSaleTicketHeadDto headDto,
                                List<UpSaleTicketLineDto> lineDtos) {
        try {
            //售货单头信息必输校验
            IntegrityValidator.begin().validate(headDto.getOrgId(), "Organization Id")
                    .validate(headDto.getCurrency(), "Curreny Type")
                    .validate(headDto.getDelieveyWays(), "Deleivery Ways")
                    .validate(headDto.getGoodTotal(), "Goods Total")
                    .validate(headDto.getInvoice(), "Invoice");
            //数字格式的校验
            Pattern pattern = Pattern.compile(SaleConstrant.PATTERN_NUMBER);
            if (!pattern.matcher(headDto.getGoodTotal()).matches()) {
                return IResult.fail("The Goods Total is invalid");
            }
            Pattern pattern1 = Pattern.compile(SaleConstrant.PATTERN_NUMBER_LENGTH);
            if (!ObjectUtil.isNullOrEmpty(headDto.getFreight())
                    && !pattern1.matcher(headDto.getFreight()).matches()) {
                return IResult.fail("The Freight is invalid");
            }
            if (!ObjectUtil.isNullOrEmpty(headDto.getPriceTotal())
                    && !pattern.matcher(headDto.getPriceTotal()).matches()) {
                return IResult.fail("The Price Total is invalid");
            }
            //售货单头参数有效性校验
            TransactionValidate check = TransactionValidate
                    .beginValidity(FndOrganizationBase.class);
            check.checkIdValidity(
                    ObjectUtil.toString(headDto.getOrgId()),
                    "ORGANIZATION_ID");
            check = TransactionValidate
                    .beginValidity(FndWorker.class);
            check.checkIdValidity(
                    ObjectUtil.toString(headDto.getWorkerId()),
                    "ID");
            //售货单行的必输参数校验
            lineDtos.forEach(line -> {
                IntegrityValidator.begin().validate(line.getItemId(), "Item Id")
                        .validate(line.getTagId(), "Tag Id");
                //售货单行的参数有效性校验
                TransactionValidate check1 = TransactionValidate
                        .beginValidity(FndItemBase.class);
                check1.checkIdValidity(
                        ObjectUtil.toString(line.getItemId()),
                        "ITEM_ID");

                check1 = TransactionValidate
                        .beginValidity(BdTag.class);
                check1.checkIdValidity(
                        ObjectUtil.toString(line.getTagId()),
                        "ID");
            });
        } catch (LightKitsBizException e) {
            return e.result();
        }
        return IResult.success();
    }

    /**
     * 售货单的创建
     *
     * @param headDto  售货单头信息
     * @param lineDtos 售货单行信息
     * @return IResult
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IResult createSaleTicket(UpSaleTicketHeadDto headDto, List<UpSaleTicketLineDto> lineDtos) {

        //检查参数
        IResult result = this.checkParams(headDto, lineDtos);
        if (!result.isSuccessful()) {
            return result;
        }
        //创建事件并插值
        BdEvent event = createSaleEventService.createEvent(headDto, "WM_SALE_ORDER_UPDATE");
        Boolean eventFlag = bdEventService.insert(event);
        if (!eventFlag) {
            throw new LightKitsBizException("Insert Sale Ticket Event Failed");
        }
        //创建售货单头并插值
        WmSalesTicket ticketHead = createSaleParamsService.createSaleHead(headDto);
        Boolean headFlag = saleTicketService.insertOrUpdate(ticketHead);
        if (!headFlag) {
            throw new LightKitsBizException("Insert Sale Ticket Head Failed");
        }
        List<UpSaleTicketLineDto> newUpLineDtos = lineDtos.stream().filter(target ->
                target.getLineStatus().equals(SaleConstrant.SALE_NEW)).collect(Collectors.toList());

        //创建售货单头行的快照
        List<BdEventRecord> bdEventRecords = new ArrayList<>();
        BdEventRecord record = createSaleEventService.createEventRecord("SALE_TICKET", "",
                event.getId(), ticketHead.getId(), "", JsonUtil.toString(ticketHead));
        bdEventRecords.add(record);
        List<WmSaleTicketLine> ticketLines = createSaleParamsService.createSaleLines(newUpLineDtos,
                ticketHead.getId(), ticketHead.getCurrency());
        if (!ObjectUtil.isNullOrEmpty(ticketLines)) {
            Boolean linesFlag = saleTicketLineService.insertBatch(ticketLines);
            if (!linesFlag) {
                throw new LightKitsBizException("Insert Sale Ticket Lines Failed");
            }
            //创建售货单行的快照
            ticketLines.forEach(line -> {
                BdEventRecord bdEventRecord = createSaleEventService.createEventRecord("SALE_TICKET_LINE",
                        "", event.getId(),
                        line.getId(), "", JsonUtil.toString(line));
                bdEventRecords.add(bdEventRecord);
            });
        }


        //创建现有量变更
        List<OnhandDTO> onhandDTOList = createChangeParams.createOnhandParams(
                headDto, event.getId(), event.getEventRequestId(), lineDtos);
        onhandDTOList.forEach(target -> {
            CheckResult<String> checkResultRes = new CheckResult<>();
            checkResultRes.setSuccessful(true);
            CheckResult<OnhandParams> checkResult = useParamsDomain.getOnhandParams(target);
            if (!checkResult.isSuccessful() || checkResult.getData() == null) {
                throw new LightKitsBizException(checkResult.getMessage());
            }
            IResult result1 = useParamsDomain.insertValue(checkResult.getData());
            if (!result1.isSuccessful()) {
                throw new LightKitsBizException(result1.getMessage());
            }
        });
        //创建子库存转移
        List<SubStockViewDTO> subStockViewDTOS = createChangeParams.createSubStockParam(
                headDto, event.getId(), event.getEventRequestId(), lineDtos);
        subStockViewDTOS.forEach(target -> {
            IResult result1 = subStockTransferDomain.subStockTransfer(target);
            if (!result1.isSuccessful()) {
                throw new LightKitsBizException(result1.getMessage());
            }
        });
        //创建取消条码转移
        List<TagViewDto> tagViewDtos = createChangeParams.createTags(lineDtos, event, headDto.getOrgId());
        if (!ObjectUtil.isNullOrEmpty(tagViewDtos)) {
            result = useTagParamsService.insertValue(tagViewDtos);
        }
        if (!result.isSuccessful()) {
            throw new LightKitsBizException(result.getMessage());
        }

        List<UpSaleTicketLineDto> upLineDto = lineDtos.stream()
                .filter(target ->
                        !target.getLineStatus().equals(SaleConstrant.SALE_CANCEL)).collect(Collectors.toList());


        //失效对应的条码
        List<CancelTagDto> cancelTagDtos = createChangeParams.createCancelTag(upLineDto, event);
        result = useTagParamsService.cancelTag(cancelTagDtos);
        if (!result.isSuccessful()) {
            throw new LightKitsBizException(result.getMessage());
        }

        //快照插值
        Boolean recordFlaag = bdEventRecordService.insertBatch(bdEventRecords);
        if (!recordFlaag) {
            throw new LightKitsBizException("Insert Sale Ticket ReCords Failed");
        }
        return IResult.success();
    }
}
